import 'dart:io';

import 'package:dio/dio.dart';
import 'package:flutter_chat/common/entity/entitys.dart';
import 'package:flutter_chat/common/store/stores.dart';
import 'package:flutter_chat/common/utils/utils.dart';

/// Http请求服务
class HttpUtil {
  /// Dio实例
  late Dio _dio;

  /// 接口地址
  final String _baseUrl = "http://192.168.108.124:8181";

  /// 超时时间 单位秒
  final int _timeout = 10;

  /// 接收数据的超时设置，单位是秒
  final int _receiveTimeout = 10;

  /// 初始化
  HttpUtil() {
    // 初始Dio
    var options = BaseOptions(
      // 请求基地址,可以包含子路径
      baseUrl: _baseUrl,
      // 连接服务器超时时间，单位是秒
      connectTimeout: Duration(seconds: _timeout),
      // 接收数据的超时设置，单位是秒
      receiveTimeout: Duration(seconds: _receiveTimeout),
      // Http请求头.
      headers: {},
      // 请求的Content-Type
      contentType: 'application/json; charset=utf-8',
      // 表示期望以那种格式(方式)接受响应数据
      responseType: ResponseType.json,
    );
    _dio = Dio(options);

    // 添加拦截器
    _dio.interceptors.add(RequestInterceptors());
  }

  /// GET请求
  Future<Response> get(
    String url, {
    Map<String, dynamic>? params,
    Options? options,
    CancelToken? cancelToken,
  }) async {
    Options requestOptions = options ?? Options();
    Response response = await _dio.get(
      url,
      queryParameters: params,
      options: requestOptions,
      cancelToken: cancelToken,
    );
    return response;
  }

  /// POST请求
  Future<Response> post(
    String url, {
    dynamic data,
    Options? options,
    CancelToken? cancelToken,
  }) async {
    var requestOptions = options ?? Options();
    Response response = await _dio.post(
      url,
      data: data ?? {},
      options: requestOptions,
      cancelToken: cancelToken,
    );
    return response;
  }

  /// PUT请求
  Future<Response> put(
    String url, {
    dynamic data,
    Options? options,
    CancelToken? cancelToken,
  }) async {
    var requestOptions = options ?? Options();
    Response response = await _dio.put(
      url,
      data: data ?? {},
      options: requestOptions,
      cancelToken: cancelToken,
    );
    return response;
  }

  /// DELETE请求
  Future<Response> delete(
    String url, {
    dynamic data,
    Options? options,
    CancelToken? cancelToken,
  }) async {
    var requestOptions = options ?? Options();
    Response response = await _dio.delete(
      url,
      data: data ?? {},
      options: requestOptions,
      cancelToken: cancelToken,
    );
    return response;
  }
}

/// 自定义拦截器
class RequestInterceptors extends Interceptor {
  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    if (options.method == "GET") {
      LogUtil.p(
          '请求[${options.method}] => 链接: ${options.path} 参数: ${options.queryParameters}');
    }
    if (options.method == "POST" ||
        options.method == "PUT" ||
        options.method == "DELETE") {
      LogUtil.p(
          '请求[${options.method}] => 链接: ${options.path} 参数: ${options.data}');
    }

    // header头加入token
    if (UserStore.to.token.isNotEmpty) {
      options.headers['token'] = UserStore.to.token;
    }

    return handler.next(options);
  }

  @override
  void onResponse(Response response, ResponseInterceptorHandler handler) {
    LogUtil.p(
        '响应码[${response.statusCode}] => 链接: ${response.requestOptions.path} 响应内容: ${response.data}');
    var data = response.data;
    var code = data["code"];
    response.data = ResponseEntity.fromJson(data);
    if (code == 401) {
      // 401 未登录
      UserStore.to.logout();
      // 提示登录过期
      ToastUtil.text("登录过期，请重新登录");
    } else if (code == 403) {
      // 403 无权限
    }
    handler.next(response);
  }

  @override
  Future<void> onError(
    DioException err,
    ErrorInterceptorHandler handler,
  ) async {
    var msg = err.response?.data["msg"];
    var data = err.response?.data["data"];
    LogUtil.p(
        '错误码[${err.response?.statusCode}] => 链接: ${err.requestOptions.path} 响应内容: $data');
    if (DioExceptionType.connectionTimeout == err.type) {
      ToastUtil.errorNotification(subTitle: "连接超时");
    }
    final exception = HttpException(msg ?? err.message);
    if (err.response != null) {
      err.response?.data = ResponseEntity.fromJson(data);
      handler.resolve(err.response!);
      return;
    }
    DioException errNext = err.copyWith(
      message: exception.message,
      error: exception,
    );
    handler.reject(errNext);
  }
}
